/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   Module Name          : com.yaodian100.ec.yihaodian.service.impl.YihaodianOrderServiceImpl
   Module Description   :

   Date Created      : 2011/12/8
   Original Author   : jeff.ma
   Team              : yaodian100
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   MODIFICATION HISTORY
   ------------------------------------------------------------------------------
   Date Modified       Modified by       Comments
   ------------------------------------------------------------------------------
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
package com.yaodian100.ec.yihaodian.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.common.dao.impl.CommonCriteria;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.utils.DateUtil;
import com.yaodian100.core.common.utils.StringUtils;
import com.yaodian100.core.logger.service.LogService;
import com.yaodian100.core.menu.entity.Option;
import com.yaodian100.core.menu.service.MenuService;
import com.yaodian100.ec.campaign.entity.Campaign;
import com.yaodian100.ec.campaign.entity.CampaignExtend;
import com.yaodian100.ec.campaign.service.CampaignService;
import com.yaodian100.ec.member.entity.Member;
import com.yaodian100.ec.member.service.AddessService;
import com.yaodian100.ec.member.service.MemberService;
import com.yaodian100.ec.order.entity.ApplyCampaign;
import com.yaodian100.ec.order.entity.OrderProduct;
import com.yaodian100.ec.order.entity.OrderProductDetail;
import com.yaodian100.ec.order.entity.Orders;
import com.yaodian100.ec.order.service.OrderService;
import com.yaodian100.ec.product.entity.Product;
import com.yaodian100.ec.product.entity.Specification;
import com.yaodian100.ec.product.service.Product2Service;
import com.yaodian100.ec.shelf.entity.Shelf;
import com.yaodian100.ec.tmall.entity.AddrMapping;
import com.yaodian100.ec.yihaodian.service.YihaodianOrderService;
import com.yihaodian.order.entity.Order;
import com.yihaodian.order.entity.OrderInfo;
import com.yihaodian.order.entity.OrderItem;

/**
 * @author jeff.ma
 * 
 */
public class YihaodianOrderServiceImpl implements YihaodianOrderService {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private OrderService ydOrderService;
	@Resource
	private JdbcTemplate jdbcTemplate;
	@Autowired
	private MemberService memberService;
	@Autowired
	private MenuService menuService;
	@Autowired
	private Product2Service productService;
	@Autowired
	private LogService logService;
	@Autowired
	private CampaignService campaignService;
	@Autowired
	private AddessService addressService;

	private String domainSrc = "yaodian100.yihaodian.com";
	private Member member;
	private Long yihaodianSpecId = 263429L; // 保修卡 specId
	private Map<String, Option> tuangouOption;

	/** default constructor */
	public YihaodianOrderServiceImpl() {
	}

	/**
	 * @return the member
	 */
	public Member getMember() {
		if (member == null) {
			// 0000928616
			member = memberService.get(menuService.get("SystemValue").getOptions().get("yihaodian_member").getMemo1());
		}
		return member;
	}

	/**
	 * @return the tuangouOption
	 */
	public Map<String, Option> getTuangouOption() {
		if (tuangouOption == null) {
			tuangouOption = menuService.get("Tuangou.yihaodian").getOptions();
		}
		return tuangouOption;
	}

	/**
	 * @param domainSrc the domainSrc to set
	 */
	public void setDomainSrc(String domainSrc) {
		this.domainSrc = domainSrc;
	}

	/**
	 * @param yihaodianSpecId the yihaodianSpecId to set
	 */
	public void setYihaodianSpecId(Long yihaodianSpecId) {
		this.yihaodianSpecId = yihaodianSpecId;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.yihaodian.service.YihaodianOrderService#syncOrder(com.yihaodian.order.entity.OrderInfo)
	 */
	@Override
	@Transactional(readOnly = false)
	public Orders syncOrder(OrderInfo orderInfo) {
		Orders result = null;

		// 查询是否有重覆外部订单编号
		CommonCriteria cri = new CommonCriteria();
		cri.addEq("domainSrc", domainSrc);
		cri.addEq("outerOrderId", orderInfo.getOrder().getOrderCode().toString());
		List<Orders> orderObjs = ydOrderService.getList(0, 1, cri, null);
		if ((orderObjs != null) && (orderObjs.size() > 0)) {
			result = orderObjs.get(0);
		}

		if (result == null) {
			/* 加入资料库重覆订单检核 */
			jdbcTemplate.update("insert into ec_order_outer values (?, ?)", domainSrc, orderInfo.getOrder().getOrderCode());

			// 外部订单物件转耀点订单物件
			result = toOrder(orderInfo);
			result = ydOrderService.save(result);

			try {
				// 记录原始外部订单物件资料
				logService.save("YihaodianOrderService", "syncOrder", Arrays.asList(result, orderInfo));
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			logger.info("ignore order: ydOrderId:{}, outerOrderId:{}", result.getOrderId(), orderInfo.getOrder()
					.getOrderCode());
		}
		return result;
	}

	/**
	 * 外部订单物件转耀点订单物件
	 * 
	 * @param orderInfo
	 * @return
	 */
	private Orders toOrder(OrderInfo orderInfo) {
		Order outerOrder = orderInfo.getOrder();

		Orders orderObj = new Orders();
		/* 写入order default资料 */
		orderObj.setDomainSrc(domainSrc);
		orderObj.setChannel_child("");
		orderObj.setClientIp("127.0.0.1");
		Date dead1 = DateUtil.getTodayAddDays(1).getTime();
		orderObj.setDeadline(DateUtil.getLastTimestamp(Calendar.HOUR_OF_DAY, dead1));// 网上支付付款期限24hr
		orderObj.setAllowSplit("N");// 不拆单
		orderObj.setCodFee(BigDecimal.ZERO); // 不支援 COD
		orderObj.setOrderSt("20"); // 预设 20 已付款, 直接转到后台
		orderObj.setPaymentSt("10"); // 已付款
		orderObj.setOrderType("3");// 外部商城訂單
		orderObj.setPaymentTp("50");// 网上支付
		orderObj.setPaymentSrc("09"); // 一号店
		orderObj.setMemo("remark:" + StringUtils.defaultIfEmpty(outerOrder.getDeliveryRemark(), " ") + ";paymentType:"
				+ outerOrder.getPayServiceType());// 备忘录
		orderObj.setMemberId(getMember().getMemberId());// 用户ID
		orderObj.setLoginId(getMember().getLoginId());// 登录ID
		orderObj.setMemberName("一号店" + outerOrder.getEndUserId().toString());// 用户名
		orderObj.setOuterOrderId(outerOrder.getOrderCode());// 外部商城订单编号
		orderObj.setChannel("yaodian100");
		orderObj.setOrderDt(outerOrder.getOrderCreateTime());// 创建时间

		if (StringUtils.isBlank(outerOrder.getInvoiceTitle()) || "个人".equals(outerOrder.getInvoiceTitle())) {
			orderObj.setInvoiceTp("01");// 发票
		} else {
			orderObj.setInvoiceTp("02");// 发票
			orderObj.setInvoiceTitle(outerOrder.getInvoiceTitle());// 发票头
		}

		// 金额部分
		orderObj.setPaymentDt(outerOrder.getOrderPaymentConfirmDate());// 付款时间
		orderObj.setTotalPrice(new BigDecimal(outerOrder.getProductAmount()).setScale(2, RoundingMode.DOWN));// 总价
		orderObj.setShipfare(new BigDecimal(outerOrder.getOrderDeliveryFee()).setScale(2, RoundingMode.DOWN)); // 运费
		orderObj.setMustPay(new BigDecimal(outerOrder.getOrderAmount()).setScale(2, RoundingMode.DOWN));
		orderObj.setCash(orderObj.getMustPay());
		// orderObj.setDiscount(new BigDecimal(outerOrder.getOrderPromotionDiscount()).setScale(2, RoundingMode.DOWN));// 折扣

		/* 处理地址问题, 错误则审单 */
		boolean checkAddr = processAddrProblem(orderObj, outerOrder);
		if (!checkAddr) {
			orderObj.setMemo(orderObj.getMemo() + ";msg:地址对应失败");
			orderObj.setOrderSt("00");
		}

		// // 有注解则审单
		// if (StringUtils.isNotBlank(outerOrder.getDeliveryRemark())) {
		// orderObj.setOrderSt("00");
		// }

		// 10min 同步後台
		orderObj.setSyncDt(DateUtil.incrementMinutes(-50).getTime());
		ydOrderService.save(orderObj); // 先存一次, 部分写法需要取得 order.orderId

		// 加入订购商品
		if ((orderInfo != null) && (orderInfo.getOrderItemList() != null)) {
			for (OrderItem itemInfo : orderInfo.getOrderItemList()) {
				String outerSpecId = itemInfo.getOuterId();
				if (StringUtils.isNotBlank(outerSpecId)) {
					addBySpec(orderObj, itemInfo, Long.parseLong(itemInfo.getOuterId()));
				} else {
					// 检核是否为团购订单
					if (getTuangouOption().get(itemInfo.getProductId().toString()) != null) {
						String specName = "";
						Long specId = null;
						for (String s1 : StringUtils.split(getTuangouOption().get(itemInfo.getProductId().toString()).getMemo1(),
								";")) {
							for (String s2 : StringUtils.split(s1, ",")) {
								if (outerOrder.getDeliveryRemark().indexOf(s2) != -1) {
									if (specName.length() > 0) {
										specName = specName + "_" + s2;
										break;
									} else {
										specName = s2;
										break;
									}
								}
							}
						}
						for (String s1 : StringUtils.split(getTuangouOption().get(itemInfo.getProductId().toString()).getMemo2(),
								";")) {
							String s2[] = StringUtils.split(s1, ":");
							if (specName.equals(s2[0])) {
								specId = Long.valueOf(s2[1]);
							}
						}
						if ((specId != null) && (itemInfo.getOrderItemNum().intValue() == 1)) {
							addBySpec(orderObj, itemInfo, specId);
							// orderObj.setOrderSt("00");
						} else {
							// 耀点仓库码不存在
							throw new CoreException("errors.yihaodian.order.create", outerOrder.getOrderCode(), specName);
						}
					} else {
						// 耀点仓库码不存在
						throw new CoreException("errors.yihaodian.order.create", outerOrder.getOrderCode());
					}
				}
			}
		}

		// 判断行销活动赠品
		addByCampaign(orderObj);

		// 加入包修卡
		addBySpec(orderObj, null, yihaodianSpecId);

		// 更新订单的joinorders
		orderObj.setJoinOrders(orderObj.getOrderId());
		orderObj.setJoinMustPay(orderObj.getMustPay());// 需支付金额

		// 订单结构异动, 金额分配到 detail
		ydOrderService.calcOrderProduct(orderObj);
		ydOrderService.calcOrderCash(orderObj);

		// 订单检核, 失败审单
		if (!valid(orderObj)) {
			orderObj.setMemo(orderObj.getMemo() + ";msg:金额检核失败");
			orderObj.setOrderSt("00");
		}

		return orderObj;
	}

	private void addByCampaign(Orders orderObj) {
		Map optional = new HashMap();
		optional.put("domain", domainSrc);
		Map<String, Campaign> campaigns = new HashMap();
		for (OrderProduct op : orderObj.getOrderProduct()) {
			// 取得所有符合商品目錄的促銷活動
			for (Campaign c : campaignService.getValidCampaign(op.getCategoryPath(), op.getProdId(), optional)) {
				ApplyCampaign ac = null;
				if (campaigns.get(c.getUuid()) == null) {
					// 該活動對此訂單是新活動
					ac = new ApplyCampaign(orderObj, c);
					campaigns.put(c.getUuid(), c);
					orderObj.getApplyCampaigns().add(ac);
				} else {
					for (ApplyCampaign a : orderObj.getApplyCampaigns()) {
						if (a.getCampaignUuid().equals(c.getUuid())) {
							ac = a;
							break;
						}
					}
				}
				// 计算
				ac.setSumAmount(ac.getSumAmount().add(op.getAmount()));
				ac.setSumQty(ac.getSumQty() + op.getQty());
				ac.getApplyProductIds().add(op.getProdId());
				ac.setApplyProductIdString(StringUtils.join(ac.getApplyProductIds(), ","));
			}
		}
		for (ApplyCampaign ac : orderObj.getApplyCampaigns()) {
			Campaign c = campaigns.get(ac.getCampaignUuid());
			for (CampaignExtend ce : c.getTypeExtends()) {
				// 檢核購買量是否滿足條件
				if ((ce.getMinQty() <= ac.getSumQty()) && (ac.getSumQty() <= ce.getMaxQty())) {
					// 檢核訂單總價是否滿足條件
					if ((ce.getMinOrderAmount().floatValue() <= ac.getSumAmount().floatValue())
							&& (ac.getSumAmount().floatValue() <= ce.getMaxOrderAmount().floatValue())) {
						ac.setActive(true);
						switch (c.getType()) {
						case C03:
							addByProd(orderObj, ce.getCampaignTypeExtension());
							break;
						default:
							break;
						}
					}
				}
			}
		}
	}

	/**
	 * 已 productId 加入订单, qty 固定为 1
	 * 
	 * @param orderObj
	 * @param prodId
	 */
	private void addByProd(Orders orderObj, String prodId) {
		Map<String, Specification> specs = productService.getSpecifications(prodId);
		if (specs.size() > 0) {
			addBySpec(orderObj, null, specs.values().iterator().next().getSpecificationId());
		}
	}

	/**
	 * 以 specId 加入订单
	 * 
	 * @param orderObj
	 * @param itemInfo
	 * @param specId
	 */
	private void addBySpec(Orders orderObj, OrderItem itemInfo, Long specId) {
		// 取得 spec 物件
		Specification spec = productService.getSpecification(specId);
		if (spec == null) {
			throw new CoreException("errors.yihaodian.order.create", orderObj.getOrderId(), itemInfo.getProductCName(),
					specId.toString());
		}
		// 取得 product 物件
		Product prod = productService.get(spec.getProductId());
		// 伪造一个上架档
		Shelf shelf = new Shelf();
		if (itemInfo != null) {
			shelf.setShelfPrice(BigDecimal.valueOf(itemInfo.getOrderItemPrice()).setScale(2, RoundingMode.DOWN));
		} else {
			shelf.setShelfPrice(BigDecimal.ZERO);
		}

		// 由 product, spec, shelf 建构 orderProduct
		OrderProduct entityProd = new OrderProduct(prod, spec, null, shelf);
		if (itemInfo != null) {
			// 若有 外部订单资讯, 将商品名称覆写, 并重设数量
			entityProd.setProdName(itemInfo.getProductCName());
			entityProd.setQty(itemInfo.getOrderItemNum().intValue());
		}
		// 重新设定价格
		entityProd.setTotalPrice(entityProd.getUnitPrice().multiply(BigDecimal.valueOf(entityProd.getQty())));
		// 加入耀点订单物件
		orderObj.addProduct(entityProd);

		// 由 product, spec, shelf 建构 orderDetail
		OrderProductDetail entityDetail = new OrderProductDetail(prod, spec, shelf);
		if (itemInfo != null) {
			entityDetail.setOuterSkuId(itemInfo.getProductId().toString());
		}
		// 根据 orderProduct 重设 orderDetail 资讯
		entityDetail.setQty(entityProd.getQty());
		entityDetail.setAmount(entityProd.getUnitPrice().multiply(BigDecimal.valueOf(entityProd.getQty())));
		entityDetail.setProdName(entityProd.getProdName());
		// 将 orderDetail 加入 orderProduct
		entityProd.addDetail(entityDetail);
	}

	private boolean processAddrProblem(Orders orderObj, Order order) {
		boolean checkOk = true;
		// 取得 AddrMapping 物件
		AddrMapping addr = addressService.convertAddr(order.getGoodReceiverProvince(), order.getGoodReceiverCity(), order
				.getGoodReceiverCounty(), order.getGoodReceiverAddress());
		// 设定订单资讯运送
		orderObj.setReceiverProvince(addr.getYdProvince());
		orderObj.setReceiverCity(addr.getYdCity());
		orderObj.setReceiverArea(addr.getYdDistrict());
		// 若 addr 不是由资料库取得. oid 为 null, 则 check 失败
		if (addr.getOid() == null) {
			checkOk = false;
		}

		// 修正上海北京问题
		if ("上海".equals(order.getGoodReceiverProvince()) || "北京".equals(order.getGoodReceiverProvince())) {
			// 一号店需将 receiverCounty 补回 receiverAddress
			orderObj.setReceiverAddr(order.getGoodReceiverCounty() + order.getGoodReceiverAddress());
		} else {
			orderObj.setReceiverAddr(order.getGoodReceiverAddress());
		}
		orderObj.setReceiverEmail(" ");
		orderObj.setReceiverExt(" ");
		orderObj.setReceiverMobile(order.getGoodReceiverMoblie());// 手机
		orderObj.setReceiverName(order.getGoodReceiverName());// 收货人姓名
		orderObj.setReceiverPhone(order.getGoodReceiverPhone());// 电话
		orderObj.setReceiverPhoneArea(" ");
		orderObj.setReceiverTp("10");
		orderObj.setReceiverZip(order.getGoodReceiverPostCode());
		return checkOk;
	}

	/**
	 * 检核订单金额主档与明细是否相符
	 * 
	 * @param order
	 * @return
	 */
	private boolean valid(Orders order) {
		boolean result = true;
		BigDecimal totalPrice = order.getTotalPrice();
		BigDecimal discount = order.getDiscount();
		BigDecimal coupon = order.getCoupon();

		for (OrderProduct op : order.getOrderProduct()) {
			BigDecimal opTotalPrice = op.getTotalPrice();
			for (OrderProductDetail od : op.getOrderProductDetail()) {
				if (od.getAmount().compareTo(od.getUnitPrice().multiply(BigDecimal.valueOf(od.getQty()))) != 0) {
					logger.error("OrderProductDetail {}, amout:{} != {}*{}", new Object[] { od.getOrderDetailId(),
							od.getAmount(), od.getUnitPrice(), od.getQty() });
					result = false;
				}
				opTotalPrice = opTotalPrice.add(od.getAmount().negate());
			}
			coupon = coupon.add(op.getCoupon().negate());
			discount = discount.add(op.getDiscount().negate());
			totalPrice = totalPrice.add(op.getTotalPrice().negate());
			if (BigDecimal.ZERO.compareTo(opTotalPrice) != 0) {
				logger.error("OrderProduct {}, totalPrice={};{}", new Object[] { op.getOrderProdId(), op.getTotalPrice(),
						opTotalPrice });
				result = false;
			}
			if (BigDecimal.ZERO.compareTo(op.getTotalPrice().add(op.getCoupon().negate()).add(op.getDiscount().negate()).add(
					op.getAmount().negate())) != 0) {
				logger.error("OrderProduct {}, totalPrice={},amount={},coupon={},discount={}", new Object[] {
						op.getOrderProdId(), op.getTotalPrice(), op.getAmount(), op.getCoupon(), op.getDiscount() });
				result = false;
			}
		}

		if (BigDecimal.ZERO.compareTo(discount) != 0) {
			logger.error("Orders {}, discount:{}/{}", new Object[] { order.getOrderId(), order.getDiscount(), discount });
			result = false;
		}
		if (BigDecimal.ZERO.compareTo(coupon) != 0) {
			logger.error("Orders {}, coupon:{}/{}", new Object[] { order.getOrderId(), order.getCoupon(), coupon });
			result = false;
		}
		if (BigDecimal.ZERO.compareTo(totalPrice) != 0) {
			logger.error("Orders {}, totalPrice:{}/{}",
					new Object[] { order.getOrderId(), order.getTotalPrice(), totalPrice });
			result = false;
		}
		if (order.getMustPay().compareTo((order.getAmount().add(order.getShipfare()))) != 0) {
			logger.error("Orders {}, mustPay:{},amount:{},shipfare:{}", new Object[] { order.getOrderId(),
					order.getMustPay(), order.getAmount(), order.getShipfare() });
			result = false;
		}
		return result;
	}
}
